﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using YArchitech.HVAC;
using YArchitech.Revit;

namespace YArchitech.Plumbing
{
	public class PipeUpdater : IUpdater
	{
		internal PipeUpdater(AddInId addinID)
		{
			this.m_updaterId = new UpdaterId(addinID, new Guid("6B8C1A6B-C30A-43BF-9694-84F03E63A330"));
		}

		internal void Register(Autodesk.Revit.DB.Document doc)
		{
			ElementFilter elementFilter = new ElementCategoryFilter(BuiltInCategory.OST_PipeCurves);
			UpdaterRegistry.RegisterUpdater(this, doc);
			UpdaterRegistry.AddTrigger(this.m_updaterId, doc, elementFilter, ChangeType.ConcatenateChangeTypes(Element.GetChangeTypeGeometry(), Element.GetChangeTypeElementAddition()));
		}

		public void Execute(UpdaterData data)
		{
			try
			{
				Document document = data.GetDocument();
				List<Pipe> addOrModifiRiserPipe = this.GetAddOrModifiRiserPipe(data, false);
				List<Pipe> addOrModifiRiserPipe2 = this.GetAddOrModifiRiserPipe(data, true);
				if ((addOrModifiRiserPipe != null && addOrModifiRiserPipe.Count >= 1) || (addOrModifiRiserPipe2 != null && addOrModifiRiserPipe2.Count >= 1))
				{
					List<List<Pipe>> list = this.GroupPipes(addOrModifiRiserPipe);
					List<List<Pipe>> list2 = this.GroupPipes(addOrModifiRiserPipe2);
					if ((list == null || list.Count < 1) && (list2 != null || list2.Count > 0))
					{
						using (List<List<Pipe>>.Enumerator enumerator = list2.GetEnumerator())
						{
							while (enumerator.MoveNext())
							{
								List<Pipe> list3 = enumerator.Current;
								if (list3 != null && list3.Count >= 1)
								{
									this.ResetTagInfo(null, list3, document);
								}
							}
							goto IL_1B3;
						}
					}
					if ((list2 == null || list2.Count < 1) && (list != null || list.Count > 0))
					{
						using (List<List<Pipe>>.Enumerator enumerator = list.GetEnumerator())
						{
							while (enumerator.MoveNext())
							{
								List<Pipe> list4 = enumerator.Current;
								if (list4 != null && list4.Count >= 1)
								{
									this.ResetTagInfo(list4, null, document);
								}
							}
							goto IL_1B3;
						}
					}
					foreach (List<Pipe> list5 in list)
					{
						if (list5 != null && list5.Count >= 1)
						{
							List<Pipe> specPipeList = this.GetSpecPipeList(list5.First<Pipe>(), ref list2);
							this.ResetTagInfo(list5, specPipeList, document);
						}
					}
					if (list2 != null && list2.Count > 0)
					{
						foreach (List<Pipe> list6 in list2)
						{
							if (list6 != null && list6.Count >= 1)
							{
								this.ResetTagInfo(null, list6, document);
							}
						}
					}
					IL_1B3:;
				}
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				throw;
			}
		}

		private List<Pipe> GetSpecPipeList(Pipe pipe, ref List<List<Pipe>> pipesList)
		{
			List<Pipe> result = null;
			if (pipe == null || pipesList == null || pipesList.Count < 1)
			{
				return result;
			}
			YJKPiping<Pipe> hypiping = new YJKPiping<Pipe>(pipe);
			for (int i = 0; i < pipesList.Count; i++)
			{
				List<Pipe> list = pipesList[i];
				if (list != null && list.Count >= 1 && hypiping.IsPipingOnLine(list.First<Pipe>()))
				{
					result = list;
					pipesList.RemoveAt(i);
				}
			}
			return result;
		}

		private void ResetTagInfo(List<Pipe> modifiPipes, List<Pipe> addPipes, Autodesk.Revit.DB.Document doc)
		{
			Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> dictionary = new Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>>();
			this.GetTotalTagAndGroupInfo(modifiPipes, ref dictionary);
			this.GetTotalTagAndGroupInfo(addPipes, ref dictionary);
			if (dictionary != null && dictionary.Count > 0)
			{
				Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> dictionary2 = new Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>>();
				int num = 0;
				using (Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>>.Enumerator enumerator = dictionary.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						KeyValuePair<Autodesk.Revit.DB.Group, List<TagMarkInformation>> item = enumerator.Current;
						if (num == 0)
						{
							dictionary2.Add(item.Key, item.Value);
							num++;
						}
						else if ((from e in dictionary2.Keys
						where e.Id.IntegerValue == item.Key.Id.IntegerValue
						select e).ToList<Autodesk.Revit.DB.Group>().Count < 1)
						{
							dictionary2.Add(item.Key, item.Value);
						}
					}
				}
				dictionary = dictionary2;
			}
			this.ResetAndCreatTagsInRiserPipes(doc, modifiPipes, dictionary);
			this.ResetAndCreatTagsInRiserPipes(doc, addPipes, dictionary);
		}

		private List<List<Pipe>> GroupPipes(List<Pipe> listPipe)
		{
			if (listPipe == null || listPipe.Count < 1)
			{
				return null;
			}
			List<List<Pipe>> list = new List<List<Pipe>>();
			for (int i = 0; i < listPipe.Count; i++)
			{
				Pipe pipe = listPipe[i];
				List<Pipe> list2 = new List<Pipe>();
				list2.Add(pipe);
				YJKPiping<Pipe> hypiping = new YJKPiping<Pipe>(pipe);
				for (int j = i + 1; j < listPipe.Count; j++)
				{
					Pipe pipe2 = listPipe[j];
					if (hypiping.IsPipingOnLine(pipe2))
					{
						list2.Add(pipe2);
						listPipe.Remove(pipe2);
					}
				}
				list.Add(list2);
			}
			return list;
		}

		private void GetTotalTagAndGroupInfo(List<Pipe> listPipe, ref Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> totalInfos)
		{
			if (listPipe == null || listPipe.Count < 1)
			{
				return;
			}
			foreach (Pipe pipe in listPipe)
			{
				Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> allMarkTagInfos = this.GetAllMarkTagInfos(pipe);
				if (allMarkTagInfos != null && allMarkTagInfos.Count >= 1)
				{
					foreach (KeyValuePair<Autodesk.Revit.DB.Group, List<TagMarkInformation>> keyValuePair in allMarkTagInfos)
					{
						if (totalInfos.Count < 1 || !totalInfos.Keys.Contains(keyValuePair.Key))
						{
							totalInfos.Add(keyValuePair.Key, keyValuePair.Value);
						}
					}
				}
			}
		}

		private Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> GetAllMarkTagInfos(Pipe pipe)
		{
			Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> dictionary = new Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>>();
			List<ElementId> detailGroupId = MarkRiserPipeUtility.GetDetailGroupId(pipe, true);
			List<TagMarkInformation> markTagInfo = MarkRiserPipeUtility.GetMarkTagInfo(pipe);
			if (detailGroupId == null || detailGroupId.Count < 1 || markTagInfo == null || markTagInfo.Count < 1)
			{
				return null;
			}
			Document document = pipe.Document;
			foreach (ElementId elementId in detailGroupId)
			{
				Autodesk.Revit.DB.Group group = document.GetElementById(elementId) as Autodesk.Revit.DB.Group;
				if (group != null)
				{
					List<ElementId> tagsID = MarkRiserPipeUtility.GetDetailGroupId(group, false);
					if (tagsID != null && tagsID.Count >= 1)
					{
						List<TagMarkInformation> value = (from tag in markTagInfo
						where tagsID.Contains(new ElementId(tag.TagId))
						select tag).ToList<TagMarkInformation>();
						dictionary.Add(group, value);
					}
				}
			}
			return dictionary;
		}

		private void ResetAndCreatTagsInRiserPipes(Autodesk.Revit.DB.Document doc, List<Pipe> listPipe, Dictionary<Autodesk.Revit.DB.Group, List<TagMarkInformation>> dicInfos)
		{
			if (listPipe == null || listPipe.Count < 1 || dicInfos == null || dicInfos.Count < 1)
			{
				return;
			}
			foreach (Pipe pipe in listPipe)
			{
				MarkRiserPipeUtility.WritePipeTagInfo(pipe, string.Empty);
				MarkRiserPipeUtility.WriteDetailGroupsInfo(pipe, string.Empty);
				string text = string.Empty;
				string value = string.Empty;
				foreach (KeyValuePair<Autodesk.Revit.DB.Group, List<TagMarkInformation>> keyValuePair in dicInfos)
				{
					Autodesk.Revit.DB.View view = doc.GetElementById(keyValuePair.Key.OwnerViewId) as Autodesk.Revit.DB.View;
					if (view != null)
					{
						string text2 = this.SetTagInfoToRiserPipe(doc, pipe, keyValuePair.Value, view);
						if (!string.IsNullOrEmpty(text2))
						{
							value = text2;
							MarkRiserPipeUtility.WriteTagsInfo(keyValuePair.Key, string.Empty);
							MarkRiserPipeUtility.WriteTagsInfo(keyValuePair.Key, text2);
							AssociationMarkInfo.WriteMarkInfoToElement(keyValuePair.Key, YArchitech.HVAC.MarkType.RiserPipe);
							if (!string.IsNullOrEmpty(text))
							{
								text += "*";
							}
							text += keyValuePair.Key.Id.IntegerValue;
						}
					}
				}
				if (!string.IsNullOrEmpty(value))
				{
					MarkRiserPipeUtility.WriteDetailGroupsInfo(pipe, text);
				}
			}
		}

		private List<TagMarkInformation> GetMarkTagInfoOnPipes(List<Pipe> listPipe)
		{
			List<TagMarkInformation> list = new List<TagMarkInformation>();
			foreach (Pipe elem in listPipe)
			{
				List<TagMarkInformation> markTagInfo = MarkRiserPipeUtility.GetMarkTagInfo(elem);
				if (markTagInfo != null && markTagInfo.Count >= 1)
				{
					list.AddRange(markTagInfo);
				}
			}
			return list;
		}

		private void SetGroupIdOnRiserPipe(Autodesk.Revit.DB.Document doc, List<Pipe> listPipe, ref List<ElementId> groupIdList, bool beModify)
		{
			if (listPipe == null || listPipe.Count < 1)
			{
				return;
			}
			if (groupIdList == null || groupIdList.Count < 1)
			{
				groupIdList = new List<ElementId>();
			}
			foreach (Pipe pipe in listPipe)
			{
				List<ElementId> detailGroupId = MarkRiserPipeUtility.GetDetailGroupId(pipe, true);
				if (detailGroupId != null && detailGroupId.Count >= 1)
				{
					if (beModify)
					{
						groupIdList.AddRange(detailGroupId);
					}
					string text = "";
					foreach (ElementId elementId in detailGroupId)
					{
						AssociationMarkInfo.WriteMarkInfoToElement(doc.GetElementById(elementId) as Group, YArchitech.HVAC.MarkType.RiserPipe);
						XYZ pointOnLineInGroup = MarkRiserPipeUtility.GetPointOnLineInGroup(doc, elementId);
						if (this.ProjectPointBeOnPipe(pipe, pointOnLineInGroup))
						{
							if (!string.IsNullOrEmpty(text))
							{
								text += "*";
							}
							text += elementId.ToString();
						}
					}
					MarkRiserPipeUtility.WriteDetailGroupsInfo(pipe, text);
				}
			}
		}

		private string SetTagInfoToRiserPipe(Autodesk.Revit.DB.Document doc, Pipe pipe, List<TagMarkInformation> tagInfoList, Autodesk.Revit.DB.View revitView)
		{
			string text = string.Empty;
			if (pipe == null || tagInfoList == null || tagInfoList.Count < 1)
			{
				return text;
			}
			string text2 = MarkRiserPipeUtility.ReadTagInfo(pipe);
			foreach (TagMarkInformation tagMarkInformation in tagInfoList)
			{
				if (this.ProjectPointBeOnPipe(pipe, tagMarkInformation.LayPoint))
				{
					if (!string.IsNullOrEmpty(text2))
					{
						text2 += "*";
					}
					if (!string.IsNullOrEmpty(text))
					{
						text += "*";
					}
					ElementId elementId = new ElementId(tagMarkInformation.TagId);
					if (!(elementId == null))
					{
						Element elementById = doc.GetElementById(elementId);
						if (elementById != null)
						{
							doc.DeleteElement(elementById);
						}
						FamilySymbol familySymbol = YJKRevitTools.GetFamilySymbol(doc, "HY_水管立管标记", BuiltInCategory.OST_PipeTags);
						if (familySymbol == null)
						{
							string markFamilyPath = UnifiedModified.GetMarkFamilyPath(doc, "HY_水管立管标记");
							doc.LoadFamily(markFamilyPath);
							familySymbol = YJKRevitTools.GetFamilySymbol(doc, "HY_水管立管标记", BuiltInCategory.OST_PipeTags);
						}
						Autodesk.Revit.DB.View markTagSuitView = this.GetMarkTagSuitView(doc, tagMarkInformation.LayPoint.Z, revitView);
						if (markTagSuitView != null)
						{
							IndependentTag independentTag = RevitVersionFuncs.NewTag(doc, markTagSuitView, new Reference(pipe), false, 0, 0, tagMarkInformation.LayPoint);
							independentTag.ChangeTypeId(familySymbol.Id);
							doc.Regenerate();
							independentTag.TagHeadPosition = new XYZ(independentTag.TagHeadPosition.X, independentTag.TagHeadPosition.Y, tagMarkInformation.LayPoint.Z);
							this.GetTagIdOrInfo(ref text, independentTag, true);
							this.GetTagIdOrInfo(ref text2, independentTag, false);
							AssociationMarkInfo.WriteMarkInfoToElement(independentTag, YArchitech.HVAC.MarkType.RiserPipe);
						}
					}
				}
			}
			MarkRiserPipeUtility.WritePipeTagInfo(pipe, text2);
			return text;
		}

		private void GetTagIdOrInfo(ref string strTag, IndependentTag tag, bool beId)
		{
			if (!string.IsNullOrEmpty(strTag))
			{
				strTag += "*";
			}
			if (beId)
			{
				strTag += tag.Id.IntegerValue;
				return;
			}
			XYZ tagHeadPosition = tag.TagHeadPosition;
			strTag = string.Concat(new object[]
			{
				strTag,
				tag.Id.IntegerValue,
				",",
				tagHeadPosition.X,
				",",
				tagHeadPosition.Y,
				",",
				tagHeadPosition.Z
			});
		}

		private void SetGroupIdOnRiserPipe(Autodesk.Revit.DB.Document doc, List<Pipe> listPipe, List<TagMarkInformation> tagInfoList)
		{
			if (listPipe == null || listPipe.Count < 1 || tagInfoList == null || tagInfoList.Count < 1)
			{
				return;
			}
			foreach (Pipe elem in listPipe)
			{
				List<TagMarkInformation> markTagInfo = MarkRiserPipeUtility.GetMarkTagInfo(elem);
				if (markTagInfo != null)
				{
					int count = markTagInfo.Count;
				}
			}
		}

		private Autodesk.Revit.DB.View GetSpecView(IndependentTag tag)
		{
			return tag.Document.GetElementById(tag.OwnerViewId) as Autodesk.Revit.DB.View;
		}

		private Autodesk.Revit.DB.View GetMarkTagSuitView(Autodesk.Revit.DB.Document doc, double layPointZValue, Autodesk.Revit.DB.View baseView)
		{
			List<Autodesk.Revit.DB.View> list = PipeUpdater.GetSameTypeViews(doc, baseView);
			if (list == null || list.Count < 1)
			{
				return null;
			}
			list = (from v in list
			where Math.Abs(v.GenLevel.Elevation - layPointZValue) < 0.0032808398950131233 || Math.Abs(v.GenLevel.Elevation + 4.9212598425196852 - layPointZValue) < 0.0032808398950131233
			select v).ToList<Autodesk.Revit.DB.View>();
			if (list == null || list.Count < 1)
			{
				return null;
			}
			list = (from v in list
			orderby v.GenLevel.Elevation
			select v).ToList<Autodesk.Revit.DB.View>();
			return list.Last<Autodesk.Revit.DB.View>();
		}

		public static List<Autodesk.Revit.DB.View> GetSameTypeViews(Autodesk.Revit.DB.Document doc, Autodesk.Revit.DB.View baseView)
		{
			List<Autodesk.Revit.DB.View> list = new List<Autodesk.Revit.DB.View>();
			if (baseView.GetParameter("视图分类-父") == null || baseView.GetParameter("视图分类-子") == null)
			{
				return list;
			}
			string b = baseView.GetParameter("视图分类-父").AsString();
			string b2 = baseView.GetParameter("视图分类-子").AsString();
			foreach (Element element in YJKElementFilter.GetElementByCategory(doc, BuiltInCategory.OST_Views))
			{
				ViewPlan viewPlan = ((Autodesk.Revit.DB.View)element) as ViewPlan;
				if (viewPlan != null && viewPlan.GetParameter("视图分类-父") != null && viewPlan.GetParameter("视图分类-子") != null && viewPlan != null && !viewPlan.IsTemplate && viewPlan.GetParameter("视图分类-父").AsString() == b && viewPlan.GetParameter("视图分类-子").AsString() == b2)
				{
					list.Add(viewPlan);
				}
			}
			return list;
		}

		private bool ProjectPointBeOnPipe(Pipe pipe, XYZ point)
		{
			bool result = false;
			YJKPiping<Pipe> hypiping = new YJKPiping<Pipe>(pipe);
			YJKLine hyline = new YJKLine(hypiping.StartConnector.Origin, hypiping.EndConnector.Origin);
			hyline.MakeUnBound();
			XYZ project = hyline.GetProject(point);
			if (hyline.IsPointOnCurveLine(project))
			{
				result = true;
			}
			return result;
		}

		private List<Pipe> GetAddOrModifiRiserPipe(UpdaterData data, bool beAdd)
		{
			Document document = data.GetDocument();
			ICollection<ElementId> collection = data.GetModifiedElementIds();
			if (beAdd)
			{
				collection = data.GetAddedElementIds();
			}
			List<Pipe> list = new List<Pipe>();
			foreach (ElementId elementId in collection)
			{
				Pipe pipe = document.GetElement(elementId) as Pipe;
				if (pipe != null && YJKRevitTools.isRiserPipe(pipe))
				{
					list.Add(pipe);
				}
			}
			return list;
		}

		private void CreatRiserPipeTag(Pipe rPipe, XYZ layPoint)
		{
			Document document = rPipe.Document;
			FamilySymbol familySymbol = YJKRevitTools.GetFamilySymbol(document, "HY_水管立管标记", BuiltInCategory.OST_PipeTags);
			IndependentTag independentTag = RevitVersionFuncs.NewTag(document, document.ActiveView, new Reference(rPipe), false, 0, 0, layPoint);
			independentTag.ChangeTypeId(familySymbol.Id);
			AssociationMarkInfo.WriteMarkInfoToElement(independentTag, YArchitech.HVAC.MarkType.RiserPipe);
			MarkRiserPipeUtility.WritePipeTagInfo(rPipe, independentTag);
		}

		public UpdaterId GetUpdaterId()
		{
			return this.m_updaterId;
		}

		public string GetUpdaterName()
		{
			return "Associative Section Updater";
		}

		public string GetAdditionalInformation()
		{
			return "Automatically moves a section to maintain its position relative to Seismic Component";
		}

		public ChangePriority GetChangePriority()
		{
            return (ChangePriority)14;
		}

		private UpdaterId m_updaterId;
	}
}
